package com.dy.yunying.biz.utils;

import com.alibaba.fastjson.JSON;
import com.pig4cloud.pig.common.core.exception.BusinessException;
import okhttp3.*;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.net.ssl.*;
import java.net.URLEncoder;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.TimeUnit;

/**
 * 封装 OkHttp 工具类
 * 
 * @author hjl
 * @date 2019年11月22日 上午9:56:50
 */
public class OkHttpUtil {
    
    /**
     * Logger for this class
     */
    private static final Logger log = LoggerFactory.getLogger(OkHttpUtil.class);

	public static final MediaType MEDIA_TYPE_JSON = MediaType.parse("application/json; charset=utf-8");
	public static final MediaType MEDIA_TYPE_TEXT_PLAN = MediaType.parse("text/plain; charset=utf-8");

    public final static int CONNECT_TIMEOUT = 60 * 5;
	public final static int READ_TIMEOUT = 60 * 30;
	public final static int WRITE_TIMEOUT = 60 * 30;
	public final static int CALL_TIMEOUT = 60 * 60;

	public static OkHttpClient okHttpClient;
	
	static {
        OkHttpUtil okHttpUtil = OkhttpHelperHolder.INSTANCE;
	}

	private OkHttpUtil() {
		OkHttpClient.Builder builder = new OkHttpClient.Builder()
				.callTimeout(CALL_TIMEOUT, TimeUnit.SECONDS)
				.pingInterval(5, TimeUnit.SECONDS)
				.connectTimeout(CONNECT_TIMEOUT, TimeUnit.SECONDS)// 连接超时
				.readTimeout(READ_TIMEOUT, TimeUnit.SECONDS)// 读取超时
				.writeTimeout(WRITE_TIMEOUT, TimeUnit.SECONDS);// 写入超时

//		 //支持HTTPS请求，跳过证书验证 TODO
//		builder.sslSocketFactory(createSSLSocketFactory());
		
		builder.hostnameVerifier(new HostnameVerifier() {
			@Override
			public boolean verify(String hostname, SSLSession session) {
				return true;
			}
		});
		okHttpClient = builder.build();
	}

	/**
	 * 使用静态内部类初始化单例okHttpClient
	 * @author hjl
	 * @date 2019年11月22日 上午10:13:35
	 */
	private static class OkhttpHelperHolder {
		public static OkHttpUtil INSTANCE = new OkHttpUtil();
	}

	/**
	 * 生成安全套接字工厂，用于https请求的证书跳过
	 * TODO
	 * @return
	 */
	@SuppressWarnings("unused")
	private SSLSocketFactory createSSLSocketFactory() {
		SSLSocketFactory ssfFactory = null;
		try {
			SSLContext sc = SSLContext.getInstance("TLS");
			sc.init(null, new TrustManager[] { new TrustAllCerts() }, new SecureRandom());
			ssfFactory = sc.getSocketFactory();
		} catch (Exception e) {
		}
		return ssfFactory;
	}

	/**
	 * 用于信任所有证书
	 */
	class TrustAllCerts implements X509TrustManager {
		@Override
		public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
		}

		@Override
		public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {

		}

		@Override
		public X509Certificate[] getAcceptedIssuers() {
			return new X509Certificate[0];
		}
	}

    /**
     * get请求
     * @param url
     * @return
     */
    public static String doGet(String url){
        return doGet(url, null);
    }
    public static String doGet(String url, HashMap<String, String> params){
        if (isBlankUrl(url)){
            return null;
        }
        Request request = getRequestForGet(url, params);
        return commonRequest(request);
    }

    /**
     * post请求
     * @param url
     * @param json
     * @return
     */
    public static String doPostJson(String url, String json){
        if (isBlankUrl(url)){
            return null;
        }
        Request request = getRequestForPostJson(url, json);
        return commonRequest(request);
    }
	public static void doAjaxPostJson(String url, String json, Callback callback){
		if (isBlankUrl(url)){
			throw new BusinessException(11, "请求链接为空");
		}
		Request request = getRequestForPostJson(url, json);
		ajaxRequest(request, callback);
	}
	public static String doPostForm(String url, Map<String, String> params){
		if (isBlankUrl(url)) {
			return null;
		}
		Request request = getRequestForPostForm(url, params);
		return commonRequest(request);
	}
	public static void doAjaxPostForm(String url, Map<String, String> params, Callback callback) {
		if (isBlankUrl(url)){
			throw new BusinessException(11, "请求链接为空");
		}
		Request request = getRequestForPostForm(url, params);
		ajaxRequest(request, callback);
	}

    private static Boolean isBlankUrl(String url){
        if (StringUtils.isBlank(url)){
            return true;
        }else{
            log.error("url is blank");
            return false;
        }
    }

    private static Request getRequestForPostJson(String url, String json) {
        RequestBody requestBody = RequestBody.create(MEDIA_TYPE_JSON, json);
        return getRequestForPost(url, requestBody);
    }


    private static Request getRequestForPostForm(String url, Map<String, String> params) {
        RequestBody requestBody = getRequestBody(params);
        return getRequestForPost(url, requestBody);
    }

    private static Request getRequestForPost(String url, RequestBody requestBody) {
        Request request = new Request.Builder()
                .url(url)
                .post(requestBody)
                .build();
        return request;
    }

    /**
     * post的请求参数，构造RequestBody
     *
     * @param bodyParams
     * @return
     */
    private static RequestBody getRequestBody(Map<String, String> bodyParams) {
        FormBody.Builder builder = new FormBody.Builder();
		if (bodyParams != null && !bodyParams.isEmpty()) {
	        for (Iterator<Entry<String, String>> iterator =  bodyParams.entrySet().iterator(); iterator.hasNext();) {
	        	Entry<String, String> entry = (Entry<String, String>) iterator.next();
	        	builder.add(entry.getKey(), entry.getValue());
			}
		}
		return builder.build();

    }

    private static Request getRequestForGet(String url) {
        Request request = new Request.Builder()
                .url(url)
                .build();
        return request;
    }

    private static Request getRequestForGet(String url, Map<String, String> params) {
        return getRequestForGet(getUrlStringForGet(url, params));
    }

    private static String getUrlStringForGet(String url, Map<String, String> params) {
        StringBuilder urlBuilder = new StringBuilder();
        urlBuilder.append(url);
        if (params != null && !params.isEmpty()) {
            urlBuilder.append("?");
            for (Entry<String, String> entry : params.entrySet()) {
                try {
                    urlBuilder.append("&").append(entry.getKey()).append("=").append(URLEncoder.encode(entry.getValue(), "UTF-8"));
                } catch (Exception e) {
                    urlBuilder.append("&").append(entry.getKey()).append("=").append(entry.getValue());
                }
            }
        }
        return urlBuilder.toString();
    }

    /**
     * 通用提交方法
     * @param request
     * @return
     */
    private static String commonRequest(Request request){
		String result = "";
		try {
			Call call = okHttpClient.newCall(request);
			Response response = call.execute();
			if (response.isSuccessful()) {
				result = response.body().string();
				log.debug("request success url:{}; result:{}", request.url().toString(), result);
			} else {
				log.error("request failure url:{}，response：{}", request.url().toString(), JSON.toJSONString(response));
			}
		} catch (Exception e) {
			log.error("request execute failure", e);
		}
		return result;
    }

	/**
	 * 异步提交方法
	 * 通过接口回调告知用户 http 的异步执行结果
	 * @param request
	 * @return
	 */
	private static void ajaxRequest(Request request, Callback callback){
		try {
			Call call = okHttpClient.newCall(request);
			call.enqueue(callback);
		} catch (Exception e) {
			log.error("request execute failure", e);
			throw new BusinessException(11, "异步请求异常");
		}
	}
}
